<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>对象遍历方式(Object traversal method)</title>
  <!-- 
  在 JavaScript 中，对象是一种重要的数据结构，遍历对象的属性和方法是常见的操作。以下是关于 JavaScript 对象遍历方法的详细说明与总结：

  1.  `for...in`  循环
  - 用法： `for...in`  循环用于遍历对象的可枚举属性，包括继承的属性。
    let person = {
      name: "张三",
      age: 25,
      gender: "男"
    };

    for (let key in person) {
      console.log(key + ": " + person[key]);
    }

  - 注意事项：使用  `for...in`  时，建议使用  `hasOwnProperty()`  方法来过滤掉继承的属性。
    for (let key in person) {
      if (person.hasOwnProperty(key)) {
        console.log(key + ": " + person[key]);
      }
    }

  2.  `Object.keys()` 
  - 用法： `Object.keys()`  方法返回一个包含对象自身可枚举属性名的数组。
    let keys = Object.keys(person);
    console.log(keys); // 输出: ["name", "age", "gender"]

  - 遍历示例：可以结合  `forEach`  方法遍历属性名。
    Object.keys(person).forEach(key => {
      console.log(key + ": " + person[key]);
    });

  3.  `Object.values()` 
  - 用法： `Object.values()`  方法返回一个包含对象自身可枚举属性值的数组。
    let values = Object.values(person);
    console.log(values); // 输出: ["张三", 25, "男"]

  - 遍历示例：可以直接遍历属性值。
    Object.values(person).forEach(value => {
      console.log(value);
    });

  4.  `Object.entries()` 
  - 用法： `Object.entries()`  方法返回一个包含对象自身可枚举属性 [key, value] 对的数组。
    let entries = Object.entries(person);
    console.log(entries); // 输出: [["name", "张三"], ["age", 25], ["gender", "男"]]

  - 遍历示例：可以直接遍历键值对。
    Object.entries(person).forEach(([key, value]) => {
      console.log(key + ": " + value);
    });

  5.  `for...of`  循环（结合  `Object.entries()` ）
  - 用法：结合  `Object.entries()`  和  `for...of`  循环遍历对象的属性。
    for (let [key, value] of Object.entries(person)) {
      console.log(key + ": " + value);
    }

  6.  `Reflect.ownKeys()` 
  - 用法： `Reflect.ownKeys()`  方法返回一个数组，包含对象自身的所有属性名，包括非枚举属性和符号属性。
    let obj = {
      name: "张三",
      age: 25,
      [Symbol('id')]: 1
    };

    let keys = Reflect.ownKeys(obj);
    console.log(keys); // 输出: ["name", "age", Symbol(id)]

  总结
  JavaScript 提供了多种方法来遍历对象的属性和方法，包括  `for...in`  循环、 `Object.keys()` 、 `Object.values()` 、 `Object.entries()` 、 `for...of`  循环以及  `Reflect.ownKeys()` 。
   -->
</head>
<body>

  <script>
    // 1.  `for...in`  循环
    // 用法： `for...in`  循环可以遍历对象的可枚举属性。
    let person = {
      name: "张三",
      age: 25,
      gender: "男"
    };

    for (let key in person) {
      console.log("1.  `for...in`  循环", key + ": " + person[key]); // 输出: name: 张三, age: 25, gender: 男
    }

    // 2.  `Object.keys()` 
    // 用法： `Object.keys()`  方法返回一个数组，包含对象自身的所有可枚举属性名。
    let keys = Object.keys(person);
    console.log("2.  `Object.keys()`", keys); // 输出: ["name", "age", "gender"]

    keys.forEach(key => {
      console.log("2.  `Object.keys()`", key + ": " + person[key]); // 输出: name: 张三, age: 25, gender: 男
    });

    // 3.  `Object.values()`
    // 用法： `Object.values()`  方法返回一个数组，包含对象自身的所有可枚举属性的值。
    let values = Object.values(person);
    console.log("3.  `Object.values()`", values); // 输出: ["张三", 25, "男"]

    values.forEach(value => {
      console.log("3.  `Object.values()`", value); // 输出: 张三, 25, 男
    })

    // 4.  `Object.entries()`
    // 用法： `Object.entries()`  方法返回一个数组，包含对象自身的所有可枚举属性的键值对数组。
    let entries = Object.entries(person);
    console.log("4.  `Object.entries()`", entries); // 输出: [["name", "张三"], ["age", 25], ["gender", "男"]]

    entries.forEach(entry => {
      console.log("4.  `Object.entries()`", entry[0] + ": " + entry[1]); // 输出: name: 张三, age: 25, gender: 男
    })

    // 5.  `for...of`  循环
    // 用法： `for...of`  循环可以遍历对象的可枚举属性值。
    for (let value of Object.values(person)) {
      console.log("5.  `for...of`  循环", value); // 输出: 张三 25 男
    }

    for (let [key, value] of Object.entries(person)) {
      console.log("5.  `for...of`  循环", key + ": " + value); // 输出: name: 张三, age: 25, gender: 男
    }

    // 对象不支持 `for...of`  循环
    // for (let value of person) {
    //   console.log("5.  `for...of`  循环", value);  // 报错: TypeError: person is not iterable
    // }

    // 6.  `Reflect.ownKeys()`
    // 用法： `Reflect.ownKeys()`  方法返回一个数组，包含对象自身的所有属性，不管属性是否可枚举。
    let allKeys = Reflect.ownKeys(person);
    console.log("6.  `Reflect.ownKeys()`", allKeys); // 输出: ["name", "age", "gender"]


  </script>
  
</body>
</html>